package edu.vt.cbil.core;

import edu.vt.cbil.dataset.*;
import edu.vt.cbil.util.BioToolbox;
import edu.vt.cbil.util.ConfigObject;

import java.util.Date;
import java.util.logging.Logger;


/**
 * The type Controller.
 *
 * @author Justin
 * @version 1.0
 * @created 09 -11月-2014 12:20:06
 */
public class Controller {
    private final int SampleCount = 1000; //the maximum number of the samples for loading
    private Logger m_log;
    private BioDataReader m_reader;
    private BioCollection m_data;
    private AnnotationDataSet p_annotation;
    private ConfigObject p_config;
    private Preprocessor m_processor;
    private SegmentProcessor m_segment;
    private DeletionClassifier m_delClassifier;
    private String curSampleId;

    /**
     * Instantiates a new Controller.
     *
     * @param pc the ConfigObject
     * @param pa the AnnotationDataSet
     */
    public Controller(ConfigObject pc, AnnotationDataSet pa) {
        m_log = Logger.getLogger("edu.vt.cbil.bacom2");

        p_config = pc;
        p_annotation = pa;

        m_data = new BioCollection(pa);
        m_data.setRoiArray(p_config.params.roiArray);

        m_reader = new BioDataReader(pc, m_data, pa);
        m_processor = new Preprocessor(m_data, p_config);

        m_segment = new SegmentProcessor(m_data, p_config);
        m_delClassifier = new DeletionClassifier(m_data, p_config);
    }

    /**
     * Run void.
     */
    public void run(boolean readAnnotation) {
        m_log.info("Start to process:");
        printParams();

        if (p_config.TestingSampleIDs.size() == 0) return;
        String[] filePair;
        String nf;
        String tf;

        switch (0) {
            case 0:
                if (readAnnotation) {
                    m_log.info("Reading annotation DB ......");
                    p_annotation.readingAnnotation(p_config.params.OnlySNP);
                }

                int n = 1;
                //for (Map.Entry<String, String[]> samplefile : p_config.SampleFiles.entrySet()) {
                for (String id : p_config.TestingSampleIDs) {

                    curSampleId = id;
                    filePair = p_config.SampleFiles.get(id);
                    nf = p_config.getSamplePath() + filePair[0];
                    tf = p_config.getSamplePath() + filePair[1];

                    m_log.info(String.format("SampleId = %s,%n \t\t\t\t <Normal:%s, %n \t\t\t\t Tumor:%s>",
                            curSampleId, nf, tf));
                    ////////Reading Raw Data////////////////

                    if (loadingBioData(curSampleId, nf, tf, new double[]{0.9, 3.0})) {
                        m_reader.clearData();
                        ///////testing
//                        createTestSample(m_data,curSampleId,3);
                        ////////////////////////////////

                        m_log.info(String.format("%n%n############%n#############\t %s :Beginning! Version: %s",
                                curSampleId, new Date()));

                        m_processor.preprocessSamples(curSampleId, true);

                        m_segment.cutSegment(curSampleId, p_config.params.smoothingCopyNumber_Width);

                        m_segment.calculateCorrelationCoefficient(p_config.params.rou_WindowsSize);
                        boolean existBalanced = m_segment.findAlleleBalancedProbe();

                        if (p_config.params.enableScanRou) {
                            m_segment.scanCorrelationCoefficient(p_config.params.rou_WindowsSize);
                        }

                        if (existBalanced) {
                            m_segment.checkDeletion();

                            m_segment.calcuateBaseLine();
                            m_data.printBaselineArray(curSampleId);

                            m_segment.normalizeByBaseLine();
                            m_segment.calcDeletionHistogram();

                            m_delClassifier.detectDeletionSegment(curSampleId);

                            /////////////******************************///////////////////

                            m_data.averagePloidy(curSampleId);
                            if (p_config.params.enable_copynumber_histogram) {
                                m_data.drawSegmentHistogram(curSampleId);
                            }

                            if (p_config.params.enable_probeset_chart) {
                                m_data.drawProbeSets(curSampleId);
                            }

                        } else {
                            m_data.results.setPloidy(curSampleId, 0);
                            m_data.results.setPurity(curSampleId, 0);
                            m_log.severe("---> don't exist Balanced Loci");
                        }

//                    m_data.calculateResults(curSampleId);
                        m_log.info(String.format("###\t %s :End! Time: %s %n%n%n", curSampleId, new Date()));

                    } else {
                        m_data.results.setPloidy(curSampleId, -1);
                        m_data.results.setPurity(curSampleId, -1);
                    }

                    m_data.releaseSample(curSampleId);

                    ////////////////////////////////
                    n++;
                    if (n > SampleCount) break;
                }
                /////////////////////////////////////
                m_data.printResultSummary();
                //m_log.info(m_data.results.printPurityHistogram());

                //m_data.drawResult();
                break;
            case 1:
///////////////////////////////////////Only Preprocessing Begin///////////////////////////////////////////
                m_log.info("Reading annotation DB ......");
                p_annotation.readingAnnotation(p_config.params.OnlySNP);

                curSampleId = p_config.TestingSampleIDs.iterator().next();
                filePair = p_config.SampleFiles.get(curSampleId);
                nf = p_config.getSamplePath() + filePair[0];
                tf = p_config.getSamplePath() + filePair[1];

                m_log.info(String.format("SampleId = %s,%n \t\t\t\t <Normal:%s, %n \t\t\t\t Tumor:%s>",
                        curSampleId, nf, tf));
                ////////Reading Raw Data////////////////
                loadingBioData(curSampleId, nf, tf, new double[]{0.9, 3.0});
                m_reader.clearData();
                ////////////////////////////////

                m_log.info(String.format("%n%n############%n#############\t %s :Beginning! Version: %s",
                        curSampleId, new Date()));

                m_processor.preprocessSamples(curSampleId, true);


///////////////////////////////////////Only Preprocessing Begin////////////////////////////////////////////
                BioToolbox.saveBioCollectionToFile(m_data, "..\\Data\\Data.bin");

                break;
            case 2:

                m_data = BioToolbox.readBioCollectionFromFile("..\\Data\\Data.bin");
                m_data.resetLogger();
                m_data.setAnnotationData(p_annotation);
                m_processor.setCollection(m_data);
                m_segment.setCollection(m_data);
                m_delClassifier.setCollection(m_data);

//////////////////////////////////////Test Segmentation Begin/////////////////////////////////////////////
                curSampleId = p_config.TestingSampleIDs.iterator().next();
                m_segment.cutSegment(curSampleId, p_config.params.smoothingCopyNumber_Width);
                m_data.drawProbeSets_forTest(curSampleId);
//////////////////////////////////////Test Segmentation End///////////////////////////////////////////////

                break;

            case 3:
                m_data = BioToolbox.readBioCollectionFromFile("..\\Data\\Data.bin");
                m_data.resetLogger();
                m_data.setAnnotationData(p_annotation);
                m_processor.setCollection(m_data);
                m_segment.setCollection(m_data);
                m_delClassifier.setCollection(m_data);

//////////////////////////////////////Test rou Begin/////////////////////////////////////////////
                curSampleId = p_config.TestingSampleIDs.iterator().next();
                m_segment.cutSegment(curSampleId, p_config.params.smoothingCopyNumber_Width);
                m_segment.scanCorrelationCoefficient(p_config.params.rou_WindowsSize);

//////////////////////////////////////Test rou End///////////////////////////////////////////////

                break;
            case 4:
                if (readAnnotation) {
                    m_log.info("Reading annotation DB ......");
                    p_annotation.readingAnnotation(p_config.params.OnlySNP);
                }

                n = 1;
                //for (Map.Entry<String, String[]> samplefile : p_config.SampleFiles.entrySet()) {
                for (String id : p_config.TestingSampleIDs) {

                    curSampleId = id;
                    filePair = p_config.SampleFiles.get(id);
                    nf = p_config.getSamplePath() + filePair[0];
                    tf = p_config.getSamplePath() + filePair[1];

                    m_log.info(String.format("SampleId = %s,%n \t\t\t\t <Normal:%s, %n \t\t\t\t Tumor:%s>",
                            curSampleId, nf, tf));
                    ////////Reading Raw Data////////////////
                    loadingBioData(curSampleId, nf, tf, new double[]{0.9, 3.0});
                    m_reader.clearData();
                    ////////////////////////////////
                    m_log.info(String.format("%n%n############%n#############\t %s :Beginning! Version: %s",
                            curSampleId, new Date()));
                }
                m_data.saveToFile(curSampleId, "");
                break;
            case 5:
//                if (readAnnotation) {
//                    m_log.info("Reading annotation DB ......");
//                    p_annotation.readingAnnotation(p_config.params.OnlySNP);
//                }

                //for (Map.Entry<String, String[]> samplefile : p_config.SampleFiles.entrySet()) {
                for (String id : p_config.TestingSampleIDs) {

                    curSampleId = id;
                    m_data.addNewSample(curSampleId);
                    m_reader.setBioDataReader(curSampleId);
                    m_reader.loadingBioDataFromImportData(curSampleId, "..\\Data\\import_data.db");

                    m_log.info(String.format("%n%n############%n#############\t %s :Beginning! Version: %s",
                            curSampleId, new Date()));

                    m_processor.preprocessSamples(curSampleId, true);

                    m_segment.cutSegment(curSampleId, p_config.params.smoothingCopyNumber_Width);

                    m_segment.calculateCorrelationCoefficient(p_config.params.rou_WindowsSize);
                    boolean existBalanced = m_segment.findAlleleBalancedProbe();

                    if (p_config.params.enableScanRou) {
                        m_segment.scanCorrelationCoefficient(p_config.params.rou_WindowsSize);
                    }

                    if (existBalanced) {
                        m_segment.checkDeletion();

                        m_segment.calcuateBaseLine();
                        m_data.printBaselineArray(curSampleId);

                        m_segment.normalizeByBaseLine();
                        m_segment.calcDeletionHistogram();

                        m_delClassifier.detectDeletionSegment(curSampleId);

                        /////////////******************************///////////////////

                        m_data.averagePloidy(curSampleId);
                        if (p_config.params.enable_copynumber_histogram) {
                            m_data.drawSegmentHistogram(curSampleId);
                        }

                        if (p_config.params.enable_probeset_chart) {
                            m_data.drawProbeSets(curSampleId);
                        }

                    } else {
                        m_data.results.setPloidy(curSampleId, 0);
                        m_data.results.setPurity(curSampleId, 0);
                        m_log.severe("---> don't exist Balanced Loci");
                    }

//                    m_data.calculateResults(curSampleId);
                    m_log.info(String.format("###\t %s :End! Time: %s %n%n%n", curSampleId, new Date()));

                    m_data.releaseSample(curSampleId);

                }
                m_data.printResultSummary();

                break;
            default:
                break;
        }
        // m_log.info(String.format("###\t %s :End! Version: %s", curSampleId, new Date()));
    }

    /**
     * loading BioData from CEL files.
     *
     * @param sampleId
     * @param nf       normal sample CEL filename
     * @param tf       tumor sample CEL filename
     * @param limit    parameter of smooth filter
     */
    private boolean loadingBioData(String sampleId, String nf, String tf, double[] limit) {
        // create a new sample data
        if (m_data.addNewSample(sampleId)) {
            //the sample<No. sampleId> will be loaded.
            m_reader.setBioDataReader(sampleId);

            if (m_reader.readingBioData(nf, tf, p_config.params.OnlySNP)) {
                if (limit != null) {
                    m_log.fine(String.format("Median Filter Threshold is [%.4f, %.4f]", limit[0], limit[1]));
                    //median filter for each probeSet.
                    m_reader.filterRawData(limit[0], limit[1]);
                }
                m_reader.calculate_SaveMeanValues(sampleId);
                return true;
            }
        }
        return false;
    }

    private void printParams() {
        m_log.info(String.format("Information of Parameters: %n \t\tsmoothingCopyNumber_Width = %d %n \t\trou_WindowsSize = %d %n " +
                        "\t\tPVALUE_THRESH = %.4f %n \t\tMIN_SEG_LENGTH = %d %n" +
                        "\t\tMIN_SEG_STEP = %d %n \t\tCOMBINE_FACTOR = %.4f %n\t\tALPHA_POSITION = %.4f",
                p_config.params.smoothingCopyNumber_Width, p_config.params.rou_WindowsSize,
                p_config.params.PVALUE_THRESH, p_config.params.MIN_SEG_LENGTH, p_config.params.MIN_SEG_STEP,
                p_config.params.COMBINE_FACTOR, p_config.params.ALPHA_POSITION));

    }

    public void createTestSample(BioCollection data, String sampleId, int chrNo) {
        BioSample sample = data.getSample(sampleId);
        Chromosome aChr = sample.getChromosome(chrNo);

        int count = aChr.getPorbeSetCount();
        int segmentCount = 8;
        int segLength = count / segmentCount;
        short[] mode = new short[segmentCount + 1];
        mode[0] = 0x11;
        mode[1] = 0x11;
        mode[2] = 0x11;
        mode[3] = 0x11;
        mode[4] = 0x11;
        mode[5] = 0x11;
        mode[6] = 0x01;
        mode[7] = 0x10;
        mode[8] = 0x01;

        int n = 0, i = 0;
        for (ProbeSet ps : aChr.probes.values()) {
            n = (int) (i / segLength);
            if (n == 8) break;

            switch (mode[n]) {
                case 0x00:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A / 100;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B / 100;
                    break;
                case 0x01:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A / 100;
                    break;
                case 0x10:
                    ;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B / 100;
                    break;
                case 0x11:

                    break;
                case 0x20:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A / 100;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B * 2;
                    break;
                case 0x02:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A * 2;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B / 10;
                    break;
                case 0x30:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A / 100;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B * 3;
                    break;
                case 0x03:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A * 3;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B / 100;
                    break;
                case 0x22:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A * 2;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B * 2;
                    break;
                case 0x04:
                    ps.data.Tumor.mean_A = ps.data.Tumor.mean_A * 4;
                    ps.data.Tumor.mean_B = ps.data.Tumor.mean_B / 100;
                    break;

            }

            i++;
        }


    }


}